/*
 * New BSD License
 * 
 * Copyright (c) 2008, Dan Crawford, Philip Nichols, Jacob Siegel, Tim Stefanski, Justin Williamson All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the distribution.
 * Neither the name of the Artemis Group nor the names of its contributors may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE. 
 * 
 * Project Artemis
 */

package ALDITS;

import java.awt.Color;
import java.awt.Graphics;

// Player object
public class Player extends MapObject {

	//Game data fields
	double direction; //direction facing, in degrees

	protected int[] startPoint;

	protected int health;

	protected double speed;

	protected int[] currentLeg;

	protected int[] nextLeg;

	protected int teamID;

	protected int clientID;

	boolean landed;

	protected String name;

	int collisions;

	int x;

	int y;

	//DRAWING FIELDS
	Points body;

	Points wings;

	Points tail;

	int radius = PLANE_LENGTH / 2;

	Color color; //color, by team?

	static final int PLANE_LENGTH = 10;

	static final int PLANE_WIDTH = 10;

	private final static Color[] myRainbow = new Color[] { Color.black,
			Color.blue, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.yellow,
			Color.RED, Color.PINK, Color.white };

	public Player(int x, int y, int clientID, int teamID, String name) {
		createPlane(x, y, myRainbow[clientID]); // creates shape object for drawing
		this.clientID = clientID;
		this.teamID = teamID;
		this.name = name;
		collisions = 0;
		startPoint = new int[] { x, y }; //$ALDITS014
		spawn();

	}
	
	public void createPlane(int x, int y, Color color) {
		this.x = x;
		this.y = y;
		body = genCircle();
		wings = genWings();
		tail = genTail();
		this.color = color;
		//this.direction = arctan(250-x,250-y); check negatives, not towards center, towards path
	}

	public static void main(String[] args) {
		Player p = new Player(1, 2, 1, 2, "1");
	}

	public void collision(int healthDeduction) {
		health -= healthDeduction;

		if (health < 0) {
			//reset player
			spawn();
		}
		speed = Map.S_MIN + (Map.S_MAX - Map.S_MIN) * health / 100.;
		collisions++;
	}

	public void spawn() {
		health = 100;
		speed = Map.S_MIN + (Map.S_MAX - Map.S_MIN) * health / 100.;
		direction = 0;
		x = startPoint[0];
		y = startPoint[1];
		currentLeg = new int[] { startPoint[0], startPoint[1] };
		nextLeg = new int[] { startPoint[0], startPoint[1] };
		//newLoc(x, y);
	}

	public void update() {
                if(x==currentLeg[0] && y==currentLeg[1]){
                    swapLegs();
                    return;}
		double remainingDistance = Map.distanceFormula(new int[] { x, y },
				currentLeg);
		if (remainingDistance < speed ) {
			swapLegs();
		} else {
                        findDir();
			x += Math.cos(direction) * speed;
			y += Math.sin(direction) * speed;
		}
		
		body = genCircle();
		wings = genWings();
		tail = genTail();
		
	}
	
	private void swapLegs() {
		x = currentLeg[0];
		y = currentLeg[1];
		currentLeg = new int[]{ nextLeg[0],nextLeg[1]};
		if(currentLeg[0]==nextLeg[0] && currentLeg[1]==nextLeg[1])
			return;
		findDir();
		//newHeading(currentLeg[0], currentLeg[1]);

	}
	
	public void newLeg(int X, int Y){
		nextLeg[0]=X;
		nextLeg[1]=Y;
		
	}
        public void nextLeg(int x, int y){
            nextLeg= new int[]{x,y};
            findDir();
        }

	private void findDir() {
		int difX = currentLeg[0] - x;
		int difY = currentLeg[1] - y;

		if (difX == 0) {
			direction = Math.PI/2*(difY>=0?1:-1);
		} else {
			direction = Math.atan(difY / difX) + (difX < 0 ? Math.PI  : 0);

		}
	}

	public boolean endOfLeg() {
		if (x == currentLeg[0] && y == currentLeg[1]) {
			return true;
		}
		return false;
	}

	public int getHealth() {
		return health;
	}

	public double getSpeed() {
		return speed;
	}

	public int getCollisions() {
		return collisions;
	}

	public String getName() {
		return name;
	}

	public int getTeamID() {
		return teamID;
	}

	public int getClientID() {
		return clientID;
	}

	public int[] getLocation() {
		int[] loc = { x, y };
		return loc;
	}

        //returns state msg for opposing player plane object
	public String toStateMsg() {
		// TODO Auto-generated method stub
            return "op" + "~" + clientID + "~" + x + "~" + y + "~" + direction;
		
	}
        
        //returns state msg for current player plane object
        public String toStateMsg_Personal() {
		// TODO Auto-generated method stub
		return "mp"  + "~" + x + "~" + y + "~" + currentLeg[0] +"~"+
                        currentLeg[1]+"~"+health+"~"+speed;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return null;
	}


	private Points genWings() {
		int[] xs = new int[3];
		int[] ys = new int[3];
		xs[0] = x - (PLANE_LENGTH / 6);
		ys[0] = y - (PLANE_WIDTH / 2);
		xs[1] = x - (PLANE_LENGTH / 6);
		ys[1] = y + (PLANE_WIDTH / 2);
		xs[2] = x + (PLANE_LENGTH / 2) - (PLANE_LENGTH / 5);
		ys[2] = y;
		Points triPoints = new Points(xs, ys);
		return triPoints;
	}

	private Points genTail() {
		int[] xs = new int[3];
		int[] ys = new int[3];
		xs[0] = x - (PLANE_LENGTH / 2);
		ys[0] = y - (PLANE_WIDTH / 4);
		xs[1] = x - (PLANE_LENGTH / 2);
		ys[1] = y + (PLANE_WIDTH / 4);
		xs[2] = x - (PLANE_LENGTH / 4);
		ys[2] = y;
		Points triPoints = new Points(xs, ys);
		return triPoints;
	}

	private Points genCircle() {
		int inc = 1;
		int half = (2 * radius + 1) / inc;
		int points[] = new int[2 * half];
		int xpoints[] = new int[2 * half];
		int count = 0;
		for (int i = -radius; i <= radius; i += inc) {
			xpoints[count] = i + x;
			xpoints[2 * half - count - 1] = xpoints[count];
			int offset = (int) ((Math
					.sqrt(Math.pow(radius, 2) - Math.pow(i, 2))) / 4);
			points[count] = y - offset;
			points[2 * half - count - 1] = y + offset;
			count++;
		}
		Points cirPoints = new Points(xpoints, points);
		return cirPoints;
	}

	public void draw(Graphics g) {
		body = genCircle();
		wings = genWings();
		tail = genTail();
		g.setColor(color);
		g.fillPolygon(body.x, body.y, 2 * (2 * radius + 1));
		g.fillPolygon(wings.x, wings.y, 3);
		g.fillPolygon(tail.x, tail.y, 3);
		g.drawLine(x, y, this.currentLeg[0], currentLeg[1]);

	}

	//subClass used to represent and pass the two list of coordiates.
	//only a helper class, synonomous to the Java class Point but works with arrays
	public class Points {
		int[] x;

		int[] y;

		Points(int[] x, int[] y) {
			this.x = x;
			this.y = y;
		}

		int[] returnX() {
			return x;
		}

		int[] returnY() {
			return y;
		}
	}

	//the structure of this demands heading change before location change
	public void newLoc(int newX, int newY) {
		for (int i = 0; i < body.x.length; i++) {
			body.x[i] += (newX - x);
			body.y[i] += (newY - y);
		}
		for (int i = 0; i < wings.x.length; i++) {
			wings.x[i] += (newX - x);
			wings.y[i] += (newY - y);
		}
		for (int i = 0; i < tail.x.length; i++) {
			tail.x[i] += (newX - x);
			tail.y[i] += (newY - y);
		}
		double dir = Math.atan((currentLeg[1] - y) / (currentLeg[0] - x));
		if (dir >= this.direction - 0.3 && dir <= this.direction + 0.3)//find error margin ie radians or degrees?
		{
			changeDirection();
		}
		this.x = newX;
		this.y = newY;

	}

	public void newHeading(int newX, int newY) {
		this.nextLeg[0] = newX;
		this.nextLeg[1] = newY;
	}

	public void changeDirection() {
		double dir = this.direction; //Saves the old direction
		this.direction = Math.atan((currentLeg[1] - y) / (currentLeg[0] - x));//calculates new heading
		double theta = this.direction - dir;
		//performs rotation using matrix multiplication
		double cosTheta = Math.cos(theta);
		double sinTheta = Math.sin(theta);
		for (int i = 0; i < body.x.length; i++) {
			int newX = (int) ((body.x[i] * cosTheta) - (body.y[i] * sinTheta));
			int newY = (int) ((body.x[i] * sinTheta) + (body.y[i] * cosTheta));
			body.x[i] = newX;
			body.y[i] = newY;
		}
		for (int i = 0; i < tail.x.length; i++) {
			int newX = (int) ((tail.x[i] * cosTheta) - (tail.y[i] * sinTheta));
			int newY = (int) ((tail.x[i] * sinTheta) + (tail.y[i] * cosTheta));
			tail.x[i] = newX;
			tail.y[i] = newY;
		}
		for (int i = 0; i < wings.x.length; i++) {
			int newX = (int) ((wings.x[i] * cosTheta) - (wings.y[i] * sinTheta));
			int newY = (int) ((wings.x[i] * sinTheta) + (wings.y[i] * cosTheta));
			wings.x[i] = newX;
			wings.y[i] = newY;
		}

	}

	public double getDirection() {
		return direction;
	}

}
